//
// connection.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <utility>
#include <vector>
#include "Connection.h"
#include "ConnectionManager.h"
#include "RequestHandler.h"
#include "RequestParser.h"

namespace http
{
	namespace server
	{

		connection::connection(boost::asio::ip::tcp::socket socket,
			ConnectionManager& manager, RequestHandler& handler)
			: m_socket(std::move(socket)),
			m_connectionManager(manager),
			m_requestHandler(handler)
		{}

		void connection::start()
		{
			read();
		}

		void connection::stop()
		{
			m_socket.close();
		}

		void connection::read()
		{
			auto self(shared_from_this());
			m_socket.async_read_some(boost::asio::buffer(m_buffer),
				[this, self] (boost::system::error_code ec, std::size_t bytes_transferred) {
				if (!ec)
				{
					request_parser::result_type result;
					std::tie(result, std::ignore) = m_requestParser.parse(
						m_request, m_buffer.data(), m_buffer.data() + bytes_transferred);

					if (result == request_parser::good)
					{
						m_requestHandler.handle_request(m_request, m_reply);
						write();
					}
					else if (result == request_parser::bad)
					{
						m_reply = Reply::stock_reply(Reply::bad_request);
						write();
					}
					else
					{
						read();
					}
				}
				else if (ec != boost::asio::error::operation_aborted)
				{
					m_connectionManager.stop(shared_from_this());
				}
			});
		}

		void connection::write()
		{
			auto self(shared_from_this());
			boost::asio::async_write(m_socket, m_reply.to_buffers(),
				[this, self] (boost::system::error_code ec, std::size_t) {
				if (!ec)
				{
					// Initiate graceful connection closure.
					boost::system::error_code ignored_ec;
					m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both,
						ignored_ec);
				}

				if (ec != boost::asio::error::operation_aborted)
				{
					m_connectionManager.stop(shared_from_this());
				}
			});
		}

	} // namespace server
} // namespace http
